#include "crane_onkey.h"

#if USE_CRANE_KEYPADC
#include "crane_keypadc.h"
#endif

#ifdef USE_ONKEY_HISR

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "../../board.h"
#include "lvgl/src/lv_misc/lv_tsrb.h"
#include "lvgl/src/lv_core/lv_group.h"

#define ONKEY_DATA_BUF_SIZE (32) /* must be power of 2 */

static char onkey_data_buf[ONKEY_DATA_BUF_SIZE];
static tsrb_t onkey_rb;
static uint8_t resume_released = 1;

extern int is_in_poweroff_chg_mode(void);
extern void onkey_wakeup(void);

static void add_onkey_queue(int state)
{
    char val = state;
    if (!tsrb_full(&onkey_rb)) {
        tsrb_add(&onkey_rb, &val, 1);
    } else {
        tsrb_drop_latest(&onkey_rb, 2);
        printf("error: add_onkey_queue, FULL, add new state=[%d]\n", val);
        tsrb_add(&onkey_rb, &val, 1);
    }
}

static int onkey_last_state = ONKEY_RELEASED;
static void get_onkey_queue(int *state)
{
    char val;
    if (tsrb_empty(&onkey_rb)) {
        *state = onkey_last_state;
    } else {
        tsrb_get(&onkey_rb, &val, 1);
        *state = val;
    }
    onkey_last_state = *state;
}

int onkey_queue_empty(void)
{
    return tsrb_empty(&onkey_rb);
}

extern void read_onkey(int *state);
void handle_onkey(struct keypad_param *val)
{
    uint32_t period;
    int onkey_curr;
    lv_indev_data_t *data = &val->data;
    static int onkey_last = ONKEY_RELEASED;
    static int long_press = 0;
    static int poweron_press = 0;
    static uint32_t press_start = 0;

    data->key = LV_KEY_END;
    val->key_event = KEY_EVENT_NONE;
    get_onkey_queue(&onkey_curr);
    if (onkey_curr != onkey_last) {
        printf("onkey = %d\n", onkey_curr);
    }

    if (onkey_curr == ONKEY_PRESSED) {
        data->state = LV_INDEV_STATE_PR;
        if (onkey_last == ONKEY_RELEASED) {
            press_start = lv_tick_get();
            val->key_event = KEY_EVENT_PRESS;
        }
        period = lv_tick_elaps(press_start);

        if ((poweron_press == 0) && (period >= KEY_POWER_ON_DURATION) && is_in_poweroff_chg_mode()) {
            poweron_press = 1;
            val->key_event = KEY_EVENT_POWER_ON;
            printf("onkey power on\n");
        } else if ((long_press == 0) && (period >= KEY_LONG_PRESS_DURATION)) {
            long_press = 1;
            val->key_event = KEY_EVENT_LONG_PRESS;
            printf("onkey long press\n");
        }
    } else { /* state == ONKEY_RELEASED */
        data->state = LV_INDEV_STATE_REL;
        if (onkey_last == ONKEY_PRESSED) {
            if((long_press == 0) && (poweron_press == 0) && resume_released) {
                val->key_event = KEY_EVENT_CLICK;
                printf("onkey click\n");
            } else {
                val->key_event = KEY_EVENT_RELEASE;
            }
        }
        resume_released = 1;
        long_press = 0;
        poweron_press = 0;
    }
    onkey_last = onkey_curr;
}

static void onkey_handler(void)
{
    int onkey_curr;
    static int onkey_last = 0;
    int onkey_miss;

    read_onkey(&onkey_curr);
    if (onkey_last == onkey_curr) {
        onkey_miss = (onkey_curr == 0)?1:0;
        printf("error: onkey miss %d!!!\n", onkey_miss);
        add_onkey_queue(onkey_miss);
    }
    add_onkey_queue(onkey_curr);
    onkey_last = onkey_curr;
    if ((onkey_curr == 1) || (onkey_miss == 1)) {
        onkey_wakeup();
    }
}

void onkey_suspend(void *arg)
{
    return;
}

void onkey_resume(void *arg)
{
    printf("onkey resume\n");
    resume_released = 0;
#if ONKEY_RESUME_RESET
    tsrb_drop(&onkey_rb, tsrb_avail(&onkey_rb));
#endif
    return;
}

void onkey_init(void)
{
    tsrb_init(&onkey_rb, onkey_data_buf, ONKEY_DATA_BUF_SIZE);
    PM812_ONKEY_BIND_INTC(onkey_handler); /* The callback is guaranteed to run in hisr by SDK */
    PM812_ONKEY_INTC_ENABLE(true);
}

#if USE_TOUCH_TRACKER
void touch_tracker_onkey(void)
{
    add_onkey_queue(1);
    add_onkey_queue(0);
    onkey_wakeup();
}
#endif
#endif
